home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / Paper Juggling / JuggleGraphics.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-18  |  26.1 KB  |  917 lines  |  [TEXT/MMCC]

  1. /*--------------------------------------------------------------------
  2.     JuggleGraphics.c
  3.     
  4.     Routines that deal with drawing and GX objects
  5.     
  6. ----------------------------------------------------------------------*/
  7.  
  8. #include "PaperJuggling.h"
  9.  
  10. //-----------------
  11. // Globals
  12. gxStyle            gThrowStyle, gHandStyle, gLabelStyle;
  13. gxInk            gThrowInk, gFadedThrowInk, gHandInk, gFadedHandInk, gLabelInk;
  14. gxViewDevice    gTheMainDevice;
  15.  
  16. //----------------------------------------------------
  17. // Initialization routine
  18.  
  19. void InitCommonGraphicObjects(void)
  20. {
  21.     gxViewDevice    screenDevices[6]; // Plan for the most outrageous
  22.     gxShape            headShape;
  23.     gxCapRecord        capRec;
  24.     gxColor            bgColor, rsltColor;
  25.     long            numDevices,
  26.                     arrowGon[] = {    3, // 3 points
  27.                                     ff(1), 0,
  28.                                     -kArrowHeadLength, kArrowHeadHeight / 2,
  29.                                     -kArrowHeadLength, -kArrowHeadHeight / 2};
  30.     
  31.     //-------------------------
  32.     // Get the device we are tuning for
  33.     // !!! This is cheesy, I should really make xor inks for each device and draw from DeviceLoop,
  34.     // but my deadline is tomorrow. This means it will draw weird on other devices, and maybe even
  35.     // crash! Oh, Boy!
  36.     numDevices = GXGetViewGroupViewDevices(gxScreenViewDevices, screenDevices);
  37.     gTheMainDevice = screenDevices[0];
  38.     
  39.     //-------------------------
  40.     // Build the throw style
  41.     gThrowStyle = GXNewStyle();
  42.     
  43.     // Make the arrow head shape
  44.     headShape = NewPolygon((gxPolygon *) arrowGon);
  45.     
  46.     // Add arrow head as a line cap and dispose it
  47.     capRec.startCap = nil;
  48.     capRec.endCap = headShape;
  49.     capRec.attributes = gxNoAttributes;
  50.     GXSetStyleCap(gThrowStyle, &capRec);
  51.     GXDisposeShape(headShape);
  52.         
  53.     // Set style pen
  54.     GXSetStylePen(gThrowStyle, kArrowPenSize);
  55.  
  56.     // Set device grid attribute for clean lines
  57.     GXSetStyleAttributes(gThrowStyle, 
  58.             GXGetStyleAttributes(gThrowStyle) | gxDeviceGridStyle);
  59.     
  60.     //-------------------------
  61.     // Build the hand style
  62.     
  63.     gHandStyle = GXNewStyle();
  64.  
  65.     // Set the font & size
  66.     SetStyleCommonFont(gHandStyle, genevaFont);
  67.     GXSetStyleTextSize(gHandStyle, kHandTextSize);
  68.     
  69.     //-------------------------
  70.     // Build the label style
  71.     
  72.     gLabelStyle = GXNewStyle();
  73.  
  74.     // Set the font, size, color, and hit test
  75.     SetStyleCommonFont(gLabelStyle, genevaFont);
  76.     GXSetStyleTextSize(gLabelStyle, kLabelTextSize);
  77.     
  78.     //-------------------------
  79.     // Build the throw inks
  80.         
  81.     SetCommonColor(&bgColor, kBGColor);
  82.  
  83.     // make the throw ink
  84.     gThrowInk = GXNewInk();
  85.     SetCommonColor(&rsltColor, kArrowColor );
  86.     SetInkFastXorTransfer(gThrowInk, gTheMainDevice, nil, &bgColor, &rsltColor);
  87.         
  88.     // make the faded throw ink and set to a 40% blend of the arrow color
  89.     gFadedThrowInk = GXNewInk();
  90.     SetInkBlendMode(gFadedThrowInk, 40);
  91.     SetInkCommonColor(gFadedThrowInk, kArrowColor);
  92.     // Get the resulting color when drawn on BGColor
  93.     SetCommonColor(&rsltColor, kBGColor);
  94.     GXCombineColor(&rsltColor, gFadedThrowInk);
  95.     GXResetInk(gFadedThrowInk); // I don't know if this is really necessary, but what the hell
  96.     SetInkFastXorTransfer(gFadedThrowInk, gTheMainDevice, nil, &bgColor, &rsltColor);
  97.  
  98.     //-------------------------
  99.     // Build the hand inks
  100.     
  101.     // make the basic hand ink
  102.     gHandInk = GXNewInk();
  103.     SetInkCommonColor(gHandInk, kHandColor);
  104.     
  105.     // make the faded hand ink, a blend with the background
  106.     gFadedHandInk = GXNewInk();
  107.     SetInkBlendMode(gFadedHandInk, 40);
  108.     SetInkCommonColor(gFadedHandInk, kHandColor);
  109.     // Get the resulting color when drawn on BGColor
  110.     SetCommonColor(&rsltColor, kBGColor);
  111.     GXCombineColor(&rsltColor, gFadedHandInk);
  112.     GXResetInk(gFadedHandInk); // I don't know if this is really necessary, but what the hell
  113.     GXSetInkColor(gFadedHandInk, &rsltColor);
  114.     
  115.     // Build the label ink
  116.     gLabelInk = GXNewInk();
  117.     SetInkCommonColor(gLabelInk, kLabelColor);
  118. }
  119.  
  120. void KillCommonGraphicObjects(void)
  121. {
  122.     GXDisposeStyle(gThrowStyle);
  123.     GXDisposeStyle(gHandStyle);
  124.     GXDisposeStyle(gLabelStyle);
  125.     GXDisposeInk(gThrowInk);
  126.     GXDisposeInk(gFadedThrowInk);
  127.     GXDisposeInk(gHandInk);
  128.     GXDisposeInk(gFadedHandInk);
  129.     GXDisposeInk(gLabelInk);
  130. }
  131.  
  132. //----------------------------------------------------
  133. // shape creation routines
  134.  
  135. // Make a new arrow to represent a throw, in the default position, perhaps faded
  136. gxShape    MakeThrowShape(JuggleHandle aJuggle, Boolean faded)
  137. {
  138.     gxShape        newShape;
  139.     gxLine        lineData;
  140.     Fixed        hGrid = (*aJuggle)->gridPt.x;
  141.     
  142.     // Initialize the line geometry
  143.     lineData.first.x = 0;
  144.     lineData.first.y = 0;
  145.     lineData.last.x = hGrid;
  146.     lineData.last.y = 0;
  147.     
  148.     // Make the line shape
  149.     newShape = GXNewLine(&lineData);
  150.     NilShapeReturnNil(newShape);
  151.     
  152.     GXSetShapeHitTest(newShape, gxCornerPointPart + gxEdgePart + gxEndCapPart,
  153.                         kArrowPenSize);
  154.     
  155.     // Set its style and ink to our global ones
  156.     GXSetShapeStyle(newShape, gThrowStyle);
  157.     if(faded)
  158.     {
  159.         GXSetShapeInk(newShape, gFadedThrowInk);
  160.         // Set shape to draw to the alternate view ports
  161.         SetShapeFadePorts(aJuggle, newShape);
  162.     }
  163.     else
  164.     {
  165.         GXSetShapeInk(newShape, gThrowInk);
  166.          SetShapeMainPort(aJuggle, newShape);
  167.     }
  168.     
  169.     return newShape;
  170. }
  171.  
  172. // Make a new text shape, L or R    
  173. gxShape    MakeHandShape(Boolean rightHand, Boolean faded)
  174. {
  175.     gxShape        newShape;
  176.  
  177.     // Make the text shape
  178.     if(rightHand)
  179.         newShape = GXNewText(1,(unsigned char*)"R",  nil);
  180.     else    // This would have to change for three armed jugglers
  181.         newShape = GXNewText(1,(unsigned char*)"L",  nil);
  182.     NilShapeReturnNil(newShape);
  183.     
  184.     // Set its style and ink to our global ones
  185.     GXSetShapeStyle(newShape, gHandStyle);
  186.     if(faded)
  187.     {
  188.         GXSetShapeInk(newShape, gFadedHandInk);
  189.     }
  190.     else
  191.     {
  192.         GXSetShapeInk(newShape, gHandInk);
  193.     }
  194.     
  195.     // Hit test defaults to gxBoundsPart, 0 tolerance, which is fine
  196.     return newShape;
  197. }
  198.  
  199. // Make a new text shape containing "Juggler X" where X is the jugglerNumber
  200. // modified to just be the number
  201. gxShape    MakeLabelShape(short jugglerNumber)
  202. {
  203.     gxShape        newShape;
  204.     char        numberText[50], labelText[50] = "Juggler ";
  205.     short        length;
  206.     
  207.     // Make the label string
  208.     NumToString((long)jugglerNumber, (StringPtr)numberText);
  209.     p2c((StringPtr)numberText);
  210.     ccat(labelText, numberText);
  211.     length = clen(labelText);
  212.     
  213.     // Make the text shape
  214.     newShape = GXNewText(length, (unsigned char*)labelText,  nil);
  215.     NilShapeReturnNil(newShape);
  216.  
  217.     // Set its style and ink to our global ones
  218.     GXSetShapeStyle(newShape, gLabelStyle);
  219.     GXSetShapeInk(newShape, gLabelInk);
  220.     
  221.     // Hit test defaults to gxBoundsPart, 0 tolerance
  222.     return newShape;
  223. }
  224.  
  225. // Make a separator shape, a dashed line, in default position (under first row or
  226. // at the left)
  227. gxShape    MakeSeparatorShape(JuggleHandle aJuggle, Boolean isHoriz)
  228. {
  229.     gxShape            newShape, dashShape;
  230.     gxLine            lineData;
  231.     gxRectangle        dashRect = {0, -fl(.5), ff(2), fl(.5)};
  232.      gxDashRecord     theDashRecord;
  233.      gxPoint            grid;
  234.      
  235.      grid = (*aJuggle)->gridPt;
  236.  
  237.     // Initialize the line geometry
  238.     if(isHoriz)
  239.     {
  240.         lineData.first.x = 0;
  241.         lineData.last.x = grid.x * ((*aJuggle)->numCounts - 1);
  242.         lineData.first.y = lineData.last.y = grid.y / 2;
  243.     }
  244.     else
  245.     {
  246.         lineData.first.x = lineData.last.x = -(grid.x / 2);
  247.         lineData.first.y = -(grid.y / 2);
  248.         lineData.last.y = (grid.y * ((*aJuggle)->numJugglers - 1)) + (grid.y / 2);
  249.     }
  250.  
  251.     // Make the line shape
  252.     newShape = GXNewLine(&lineData);
  253.     NilShapeReturnNil(newShape);
  254.     
  255.     // Make the dash shape
  256.     dashShape = GXNewRectangle(&dashRect);
  257.     NilShapeReturnNil(dashShape);
  258.     
  259.     // Add the dash and dispose it
  260.     theDashRecord.attributes = gxAutoAdvanceDash;
  261.     theDashRecord.dash = dashShape;
  262.     theDashRecord.advance = ff(4); 
  263.     theDashRecord.phase = 0; 
  264.     theDashRecord.scale = ff(1); 
  265.     GXSetShapeDash(newShape, &theDashRecord);
  266.     GXDisposeShape(dashShape);
  267.     
  268.     // Set the color, pen and hit test
  269.     // SetShapeCommonColor(newShape, kSeparatorColor);
  270.     GXSetShapePen(newShape, ff(1));
  271.     if(isHoriz) // turn off hit testing for horizontal separators
  272.         GXSetShapeHitTest(newShape, gxNoPart, ff(0));
  273.     
  274.     return newShape;
  275. }
  276.  
  277. // Build a picture that is a row of Rs and Ls, in the default position (first row)
  278. gxShape MakeJugglerShape(JuggleHandle aJuggle, Boolean rightFirst, short jugglerNumber)
  279. {
  280.     short        numHandPairs, counter;
  281.     Fixed        twiceHGrid, repeatDist;
  282.     gxShape        labelShape, firstShape, secondShape, newPicture;
  283.     
  284.     // Make the new picture
  285.     newPicture = GXNewShape(gxPictureType);
  286.     NilShapeReturnNil(newPicture);
  287.  
  288.     // Set the unique items shape attribute so a new copy is made for each hand
  289.     GXSetShapeAttributes(newPicture,
  290.                             GXGetShapeAttributes(newPicture) | gxUniqueItemsShape);
  291.     
  292.     // make and add the label shape
  293.     labelShape = MakeLabelShape(jugglerNumber);
  294.     NilShapeReturnNil(labelShape);
  295.     MoveShapeCenterTo(labelShape, -(*aJuggle)->gridPt.x - ff(2), ff(0));
  296.     AddToPicture(newPicture, labelShape, nil, nil, nil);
  297.     GXDisposeShape(labelShape);
  298.     labelShape = nil;
  299.      
  300.     // figure out the number of pairs of hands and the distance we need to move them
  301.     numHandPairs = ((*aJuggle)->numCounts + 1) / 2;
  302.     twiceHGrid = (*aJuggle)->gridPt.x * 2;
  303.     repeatDist = (*aJuggle)->gridPt.x * (*aJuggle)->numCounts; 
  304.     
  305.     // Make the solid hand shapes
  306.     firstShape = MakeHandShape(rightFirst, false);
  307.     NilShapeReturnNil(firstShape);
  308.     MoveShapeCenterTo(firstShape, ff(0), ff(0));
  309.     secondShape = MakeHandShape(!rightFirst, false);
  310.     NilShapeReturnNil(secondShape);
  311.     MoveShapeCenterTo(secondShape, (*aJuggle)->gridPt.x, ff(0));
  312.     
  313.     // Add the solid hand shapes, all in a row
  314.     counter = numHandPairs;
  315.     while(counter-- > 0)
  316.     {
  317.         AddToPicture(newPicture, firstShape, nil, nil, nil);
  318.         GXMoveShape(firstShape, twiceHGrid, 0);
  319.         AddToPicture(newPicture, secondShape, nil, nil, nil);
  320.         GXMoveShape(secondShape, twiceHGrid, 0);
  321.     }
  322.     
  323.     // Clean up
  324.     GXDisposeShape(firstShape);
  325.     GXDisposeShape(secondShape);
  326.     
  327.     // Make the faded hand shapes
  328.     firstShape = MakeHandShape(rightFirst, true);
  329.     NilShapeReturnNil(firstShape);
  330.     MoveShapeCenterTo(firstShape, repeatDist, ff(0));
  331.     secondShape = MakeHandShape(!rightFirst, true);
  332.     NilShapeReturnNil(secondShape);
  333.     MoveShapeCenterTo(secondShape, repeatDist + (*aJuggle)->gridPt.x, ff(0));
  334.     
  335.     // Add the faded hand shapes, all in a row
  336.     counter = numHandPairs;
  337.     while(counter-- > 0)
  338.     {
  339.         AddToPicture(newPicture, firstShape, nil, nil, nil);
  340.         GXMoveShape(firstShape, twiceHGrid, 0);
  341.         AddToPicture(newPicture, secondShape, nil, nil, nil);
  342.         GXMoveShape(secondShape, twiceHGrid, 0);
  343.     }
  344.     
  345.     // Clean up again
  346.     GXDisposeShape(firstShape);
  347.     GXDisposeShape(secondShape);
  348.     
  349.     return newPicture;
  350. }
  351.  
  352. // Sets up a special shape for printing, with no weird colors or modes,
  353. // just black and white copy mode
  354. // !!! Should add in the faded throws, in gray, and print the title, too.
  355. gxShape MakePrintingShape(JuggleHandle aJuggle)
  356. {
  357.     gxPoint            grid;
  358.     gxShape            pageShape;
  359.     gxInk            defaultInk;
  360.     
  361.     // First make a copy of the shape
  362.     pageShape = GXCopyDeepToShape(nil, (*aJuggle)->docPage);
  363.     if(pageShape != nil)
  364.     {
  365.         // Move it over to account for the mapping offset of the content port
  366.         //(We can't get it directly from the port, as it might be scrolled, and
  367.         // scrolling changes the mapping)
  368.         grid = (*aJuggle)->gridPt;
  369.         GXMoveShape(pageShape, grid.x + (grid.x / 2),     // 1 and a half times x
  370.                         grid.y / 2);                    // half of y
  371.         
  372.         // Set all shapes to draw in black, copy mode
  373.         defaultInk = GXNewInk();
  374.         SetDeepShapeInk(pageShape, defaultInk);
  375.         GXDisposeInk(defaultInk);
  376.         
  377.         // Add in the faded throws
  378.     }
  379.     return pageShape;
  380. }
  381.  
  382. // !!! Needs error checking
  383. OSErr SetUpJuggleViewPorts(WindowPtr window, JuggleHandle aJuggle)
  384. {
  385.     gxViewPort        docPort, newPort;
  386.     gxViewGroup        group;
  387.     gxMapping        portMapping;
  388.     gxShape            clipShape;
  389.     gxRectangle        clipRect;
  390.     gxPoint            grid = (*aJuggle)->gridPt;
  391.     
  392.     // Get the content port and set its mapping
  393.     docPort = (*aJuggle)->docPort;
  394.     GXGetViewPortMapping(docPort, &portMapping);
  395.     MoveMapping(&portMapping, 
  396.                     grid.x + (grid.x / 2), // 1 and a half times x
  397.                     grid.y / 2);
  398.     GXSetViewPortMapping(docPort, &portMapping);
  399.     
  400.     // Set up rectangle to enclose the repeatable unit of the juggle
  401.     // (in docPort space)
  402.     clipRect.left = -(grid.x / 2);
  403.     clipRect.top = -(grid.y / 2);
  404.     clipRect.right = (grid.x * (*aJuggle)->numCounts) - (grid.x / 2);
  405.     clipRect.bottom = ff(32000); // no clip on the bottom
  406.     clipShape = GXNewRectangle(&clipRect);
  407.     
  408.     // Get the view group for the window
  409.     group = GXGetViewPortViewGroup(docPort);
  410.     
  411.     // Make the before port and save in the juggle
  412.     newPort = GXNewViewPort(group);
  413.     GXSetViewPortClip(newPort, clipShape);
  414.     ResetMapping(&portMapping);
  415.     MoveMapping(&portMapping, 
  416.                     -(grid.x * (*aJuggle)->numCounts), // shift left one juggle
  417.                     0);
  418.     GXSetViewPortMapping(newPort, &portMapping);
  419.     GXSetViewPortParent(newPort, docPort);
  420.     (*aJuggle)->beforePort = newPort;
  421.     
  422.     // Make the after port and save in the juggle
  423.     newPort = GXNewViewPort(group);
  424.     GXMoveShape(clipShape, grid.x * (*aJuggle)->numCounts, 0);
  425.     GXSetViewPortClip(newPort, clipShape);
  426.     ResetMapping(&portMapping);
  427.     MoveMapping(&portMapping, 
  428.                     grid.x * (*aJuggle)->numCounts, // shift right one juggle
  429.                     0);
  430.     GXSetViewPortMapping(newPort, &portMapping);
  431.     GXSetViewPortParent(newPort, docPort);
  432.     (*aJuggle)->afterPort = newPort;
  433.     
  434.     // Clean up
  435.     GXDisposeShape(clipShape); clipShape = nil;
  436.  
  437.     return noErr;
  438. }
  439.  
  440. // Make the picture shapes that contain the jugglers and throws. Add them
  441. // into one containing picture shape and return it. Also create the 
  442. // arrow shape for the throws
  443. gxShape SetUpJuggleGraphics(WindowPtr window, JuggleHandle aJuggle)
  444. {
  445.     gxShape    pagePict, throwsPict, fadedThrowsPict, jugglersPict, sepsPict, juggler, sep;
  446.     short    count;
  447.     
  448.     //------------------------
  449.     // Set up the view port hierarchy
  450.     if(SetUpJuggleViewPorts(window, aJuggle) != noErr)
  451.         return nil;
  452.     
  453.     //------------------------
  454.     // make the jugglers pict
  455.     jugglersPict = GXNewShape(gxPictureType);
  456.     NilShapeReturnNil(jugglersPict);
  457.     
  458.     // Make it draw in the main port
  459.     SetShapeMainPort(aJuggle, jugglersPict);
  460.     
  461.     // add the right number of jugglers
  462.     for(count = 0; count < (*aJuggle)->numJugglers; count++)
  463.     {
  464.         juggler = MakeJugglerShape(aJuggle, true, count + 1);
  465.         if(count > 0) // prevents warning: geometry_unnaffected
  466.             GXMoveShape(juggler, 0, (*aJuggle)->gridPt.y * count);
  467.         AddToPicture(jugglersPict, juggler, nil, nil, nil);
  468.         GXDisposeShape(juggler);
  469.     }
  470.  
  471.     //------------------------
  472.     // make the throws pict
  473.     throwsPict = GXNewShape(gxPictureType);
  474.     NilShapeReturnNil(throwsPict);
  475.  
  476.     // Make it draw in the main port
  477.     SetShapeMainPort(aJuggle, throwsPict);
  478.     
  479.     //------------------------
  480.     // make the faded throws pict
  481.     fadedThrowsPict = GXNewShape(gxPictureType);
  482.     NilShapeReturnNil(fadedThrowsPict);
  483.  
  484.     // Set shape to draw to the alternate view ports
  485.     SetShapeFadePorts(aJuggle, fadedThrowsPict);
  486.     
  487.     //------------------------
  488.     // make the separators pict
  489.     sepsPict = GXNewShape(gxPictureType);
  490.     NilShapeReturnNil(sepsPict);
  491.  
  492.     // Make it draw in the main port
  493.     SetShapeMainPort(aJuggle, sepsPict);
  494.     
  495.     GXSetShapeAttributes(sepsPict,
  496.                             GXGetShapeAttributes(sepsPict) | gxUniqueItemsShape);
  497.  
  498.     // Make one vertical separator
  499.     sep = MakeSeparatorShape(aJuggle, false);
  500.     NilShapeReturnNil(sep);
  501.  
  502.     // add it thrice, once at each end of the juggle, and once in the middle
  503.     AddToPicture(sepsPict, sep, nil, nil, nil);
  504.     GXMoveShape(sep, (*aJuggle)->numCounts * (*aJuggle)->gridPt.y, 0);
  505.     AddToPicture(sepsPict, sep, nil, nil, nil);
  506.     GXMoveShape(sep, (*aJuggle)->numCounts * (*aJuggle)->gridPt.y, 0);
  507.     AddToPicture(sepsPict, sep, nil, nil, nil);
  508.     GXDisposeShape(sep); sep = nil;
  509.     
  510.     // Make one horizontal separator
  511.     sep = MakeSeparatorShape(aJuggle, true);
  512.     NilShapeReturnNil(sep);
  513.  
  514.     // add the right number of horiz. separators and dispose the original
  515.     count = (*aJuggle)->numJugglers - 1;
  516.     while(count-- > 0)
  517.     {
  518.         AddToPicture(sepsPict, sep, nil, nil, nil);
  519.         GXMoveShape(sep, 0, (*aJuggle)->gridPt.y);
  520.     }
  521.     GXDisposeShape(sep); sep = nil;    
  522.     
  523.     //------------------------
  524.     // get the page pict
  525.     pagePict = (*aJuggle)->docPage;
  526.     
  527.     // Add the other pictures to the page pict
  528.     AddToPicture(pagePict, jugglersPict, nil, nil, nil);
  529.     AddToPicture(pagePict, sepsPict, nil, nil, nil);
  530.     AddToPicture(pagePict, throwsPict, nil, nil, nil);
  531.  
  532.     // Save the appropriate references in the juggle structure
  533.     (*aJuggle)->jugglersPict = jugglersPict;
  534.     (*aJuggle)->throwsPict = throwsPict;    
  535.     (*aJuggle)->fadedThrowsPict = fadedThrowsPict;    
  536.     (*aJuggle)->sepsPict = sepsPict;    
  537.     
  538.     // return the top level page pict
  539.     return pagePict;
  540. }
  541.  
  542. void CleanUpJuggleShapes(WindowPtr window)
  543. {
  544.     JuggleHandle    aJuggle = GetWindowJuggle(window);
  545.  
  546.     GXDisposeShape((*aJuggle)->jugglersPict);     // Dispose of this doc's jugglers picture.
  547.     GXDisposeShape((*aJuggle)->throwsPict);         // Dispose of this doc's throws picture.
  548.     GXDisposeShape((*aJuggle)->fadedThrowsPict);     // Dispose of this doc's faded throws picture.
  549.     GXDisposeShape((*aJuggle)->sepsPict);             // Dispose of this doc's separators picture.
  550. }
  551.  
  552. //----------------------------------------------------
  553. // graphics utility routines
  554.  
  555. // Add the throw shape(s) to the throws pict(s), drawing it(them)
  556. void AddNewThrowShape(JuggleHandle aJuggle, gxLine *line, Boolean draw)
  557. {
  558.     gxShape        arrow, fadeArrow;
  559.     
  560.     // Make an arrow shape and set its geometry
  561.     arrow = MakeThrowShape(aJuggle, false);
  562.     GXSetLine(arrow, line);
  563.     
  564.     // Make a faded arrow shape and set its geometry
  565.     fadeArrow = MakeThrowShape(aJuggle, true);
  566.     GXSetLine(fadeArrow, line);
  567.  
  568.     // add them to the front of their pictures
  569.     GXSetPictureParts((*aJuggle)->throwsPict, 1, 0, 1, &arrow, nil, nil, nil);
  570.     GXSetPictureParts((*aJuggle)->fadedThrowsPict, 1, 0, 1, &fadeArrow, nil, nil, nil);
  571.  
  572.     // Draw them
  573.     if(draw)
  574.     {
  575.         GXDrawShape(arrow);
  576.         GXDrawShape(fadeArrow);
  577.     }
  578.     
  579.     // clean up
  580.     GXDisposeShape(arrow);
  581.     GXDisposeShape(fadeArrow);
  582. }
  583.  
  584. // Remove the throw shape from the throws pict, erasing first
  585. void RemoveThrowShape(JuggleHandle aJuggle, short shapeIndex)
  586. {
  587.     gxShape        throwShape, fadedThrowShape;
  588.     
  589.     // Get shapes
  590.     GetPictureItem((*aJuggle)->throwsPict, shapeIndex, &throwShape, nil, nil, nil);
  591.     GetPictureItem((*aJuggle)->fadedThrowsPict, shapeIndex, &fadedThrowShape, nil, nil, nil);
  592.     
  593.     // Erase them by drawing (xor, remember)
  594.     GXDrawShape(throwShape);
  595.     GXDrawShape(fadedThrowShape);
  596.     
  597.     // Remove shapes from throwsPict
  598.     GXSetPictureParts((*aJuggle)->throwsPict, shapeIndex, 1, 0, nil, nil, nil, nil);
  599.     GXSetPictureParts((*aJuggle)->fadedThrowsPict, shapeIndex, 1, 0, nil, nil, nil, nil);
  600. }
  601.  
  602. // Change a throw shape, erasing the old and drawing the new
  603. void MoveThrowShape(JuggleHandle aJuggle, short shapeIndex, gxLine *newLine)
  604. {
  605.     gxShape        throwShape, fadedThrowShape, oldShape, oldFadedShape;
  606.     
  607.     // Get shapes
  608.     GetPictureItem((*aJuggle)->throwsPict, shapeIndex, &throwShape, nil, nil, nil);
  609.     GetPictureItem((*aJuggle)->fadedThrowsPict, shapeIndex, &fadedThrowShape, nil, nil, nil);
  610.     
  611.     // Copy the shapes
  612.     oldShape = GXCopyToShape(nil, throwShape);
  613.     NilShapeReturn(oldShape);
  614.     oldFadedShape = GXCopyToShape(nil, fadedThrowShape);
  615.     NilShapeReturn(oldFadedShape);
  616.     
  617.     // Set new line, erase, and draw
  618.     GXSetLine(throwShape, newLine);
  619.     GXSetLine(fadedThrowShape, newLine);
  620.     GXDrawShape(oldShape);
  621.     GXDrawShape(throwShape);
  622.     GXDrawShape(oldFadedShape);
  623.     GXDrawShape(fadedThrowShape);
  624.     
  625.     // Clean up
  626.     GXDisposeShape(oldShape);
  627.     GXDisposeShape(oldFadedShape);
  628. }
  629.                 
  630.  
  631. // Empty out the throws picture and rebuild it from the connections data
  632. void RebuildThrowsPict(JuggleHandle aJuggle)
  633. {
  634.     gxShape        throwsPict, fadedThrowsPict;
  635.     Fixed        handRadius;
  636.     short         timeCount, jugglerCount;
  637.     
  638.     handRadius = kHandRadius;
  639.     throwsPict = (*aJuggle)->throwsPict;
  640.     fadedThrowsPict = (*aJuggle)->fadedThrowsPict;
  641.     
  642.     // Remove all shapes from the picts
  643.     GXSetPictureParts(    throwsPict,        // the picture
  644.                         1,                // first item to remove
  645.                         gxSelectToEnd,    // remove all the way to the end
  646.                         0,                // nothing being inserted
  647.                         nil,            // no shapes, styles, inks, or transforms
  648.                         nil,
  649.                         nil,
  650.                         nil    );
  651.     GXSetPictureParts(    fadedThrowsPict, 1, gxSelectToEnd, 0, nil, nil, nil, nil);
  652.     
  653.     // build it back up again
  654.     for(timeCount = 1; timeCount <= (*aJuggle)->numCounts; timeCount++)
  655.     {
  656.         for(jugglerCount = 1; jugglerCount <= (*aJuggle)->numJugglers; jugglerCount++)
  657.         {
  658.             HandPtr    hand = GetIndexedHand(aJuggle, timeCount, jugglerCount, false);
  659.             if(hand != nil && hand->sink.time > 0) // if there's a sink, make a throw for it
  660.             {
  661.                 gxLine    aLine;
  662.                 HandLoc    aLoc;
  663.                 
  664.                 // Set the first point
  665.                 aLoc.time = timeCount;
  666.                 aLoc.juggler = jugglerCount;
  667.                 HandLocToPoint(aJuggle, &aLoc, &aLine.first);
  668.                 aLine.first.x += handRadius; // move off the hand
  669.                 
  670.                 // Set the last point. If the throw wraps around, set the 
  671.                 // last point off the right edge
  672.                 if(hand->sink.time > timeCount)
  673.                     aLoc.time = hand->sink.time;
  674.                 else
  675.                     aLoc.time = hand->sink.time + (*aJuggle)->numCounts;
  676.                 aLoc.juggler = hand->sink.juggler;
  677.                 HandLocToPoint(aJuggle, &aLoc, &aLine.last);
  678.                 aLine.last.x -= handRadius; // move off the hand
  679.                 
  680.                 // Add the new throw shape
  681.                 AddNewThrowShape(aJuggle, &aLine, false);
  682.             }
  683.         }
  684.     }
  685. }
  686.  
  687. void MoveJugglerInPict(JuggleHandle aJuggle, short fromRow, short toRow)
  688. {
  689.     gxShape    jugglersPict, movedShape, theShapes[kMaxJugglers];
  690.     short    numJugglers, rowDistance, increment, index;
  691.     
  692.     jugglersPict = (*aJuggle)->jugglersPict;
  693.     
  694.     // Get the shapes
  695.     numJugglers = GXGetPicture(jugglersPict, theShapes, nil, nil, nil);
  696.     
  697.     // Sanity Check
  698. /*     if(numJugglers != (*aJuggle)->numJugglers)
  699.     {
  700.         SysBeep(10);
  701.         return;
  702.     }
  703.  */    
  704.     // see how far we moved
  705.     rowDistance = toRow - fromRow;
  706.     
  707.     index = fromRow - 1;
  708.     if(rowDistance < 0)
  709.     {
  710.         // moving up
  711.         increment = -1;
  712.         rowDistance = -rowDistance;
  713.     }
  714.     else
  715.     {
  716.         // moving down
  717.         increment = 1;
  718.     }
  719.     
  720.     // Save off a copy of the moved shape, and move its screen position
  721.     movedShape = theShapes[fromRow - 1];
  722.     GXMoveShape(movedShape, 0, (*aJuggle)->gridPt.y * increment * rowDistance);
  723.     
  724.     // Move the block of shapes between the from and to rows
  725.     while(rowDistance-- > 0)
  726.     {
  727.         // move its position in the picture
  728.         theShapes[index] = theShapes[index + increment];
  729.         
  730.         // Move its position on screen
  731.         GXMoveShape(theShapes[index], 0, -((*aJuggle)->gridPt.y * increment));
  732.         
  733.         // next shape
  734.         index += increment;
  735.     }
  736.     
  737.     // insert moved juggler in destination row
  738.     theShapes[toRow - 1] = movedShape;
  739.     
  740.     // Restore picture
  741.     GXSetPicture(jugglersPict, numJugglers, theShapes, nil, nil, nil);
  742. }
  743.  
  744. void SwitchJugglerHands(JuggleHandle aJuggle, short jugglerNum)
  745. {
  746.     gxShape         firstHand, oldJuggler, newJuggler;
  747.     unsigned char    handText[2] = "R";
  748.     short            rowNum;
  749.     
  750.     rowNum = JugglerToRow(aJuggle, jugglerNum);
  751.     
  752.     // Get the juggler
  753.     GetPictureItem((*aJuggle)->jugglersPict, rowNum, &oldJuggler, nil, nil, nil);
  754.     
  755.     // Get the text in the first hand
  756.     GetPictureItem(oldJuggler, 2, &firstHand, nil, nil, nil);
  757.     GXGetText(firstHand, nil, handText, nil);
  758.     
  759.     // Make the right replacement, position it, and replace it
  760.     newJuggler = MakeJugglerShape(aJuggle, (handText[0] != 'R'), jugglerNum);
  761.     if(rowNum > 1)  // prevents warning: geometry_unnaffected
  762.         GXMoveShape(newJuggler, 0, (*aJuggle)->gridPt.y * (rowNum - 1));
  763.     SetPictureItem((*aJuggle)->jugglersPict, rowNum, newJuggler, nil, nil, nil);
  764.     GXDisposeShape(newJuggler);
  765. }
  766.  
  767. void ChangeJugglerLabel(JuggleHandle aJuggle, short juggler, short newId)
  768. {
  769.     gxShape    jugglerShape, labelShape;
  770.     short    row;
  771.     
  772.     row = JugglerToRow(aJuggle, juggler);
  773.     GetPictureItem((*aJuggle)->jugglersPict, row, &jugglerShape, nil, nil, nil);
  774.     if(jugglerShape != nil)
  775.     {
  776.         // get label
  777.         GetPictureItem(jugglerShape, 1, &labelShape, nil, nil, nil);
  778.         if(labelShape != nil)
  779.         {
  780.             char        numberText[50], labelText[50] = "Juggler ";
  781.             long        length;
  782.  
  783.             // Make the new label string
  784.             NumToString((long)newId, (StringPtr)numberText);
  785.             p2c((StringPtr)numberText);
  786.             ccat(labelText, numberText);
  787.             length = clen(labelText);
  788.             
  789.             // Set it
  790.             GXSetText(labelShape, length, (unsigned char*)labelText, nil);
  791.         }
  792.     }
  793. }
  794.  
  795. // Modelled after SetDeepShapeTransform in the transform library
  796. void SetDeepShapeInk(gxShape sh, gxInk ink)
  797. {
  798.     if (GXGetShapeType(sh) == gxPictureType) {
  799.         register short count = GXGetPicture(sh, nil, nil, nil, nil);
  800.         gxShape itemShape;
  801.         gxInk itemInk;
  802.         
  803.         while (count) {
  804.             GXGetPictureParts(sh, count, 1, &itemShape, nil, &itemInk, nil);
  805.             if (itemInk) {
  806.                 gxStyle     itemStyle;
  807.                 gxTransform itemXform;
  808.                 
  809.                 GXGetPictureParts(sh, count, 1, &itemShape, &itemStyle, &itemInk, &itemXform);
  810.                 GXSetPictureParts(sh, count, 1, 1, &itemShape, &itemStyle, &ink, &itemXform);
  811.             }
  812.             SetDeepShapeInk(itemShape, ink);
  813.             count--;
  814.         }
  815.     }
  816.     GXSetShapeInk(sh, ink);
  817. }
  818.  
  819. RgnHandle GetShapeBoundsRgn(gxShape shape)
  820. {
  821.     gxRectangle        bounds;
  822.     RgnHandle        rgn;
  823.     
  824.     GXGetShapeLocalBounds(shape, &bounds);
  825.     rgn = NewRgn();
  826.     SetRectRgn(rgn, FixedRound(bounds.left), FixedRound(bounds.top),
  827.                 FixedRound(bounds.right), FixedRound(bounds.bottom));
  828.     return rgn;
  829. }
  830.  
  831. Rect *GetShapeBoundsQDRect(gxShape shape, Rect *rect)
  832. {
  833.     gxRectangle        bounds;
  834.     
  835.     GXGetShapeLocalBounds(shape, &bounds);
  836.     return FixedRectToShort(&bounds, rect);
  837. }
  838.  
  839. Point GetQDWindowOrigin(WindowPtr window)
  840. {
  841.     gxViewPort        docPort;
  842.     gxPoint            theGXPt;
  843.     Point            theQDPt;
  844.     
  845.     theQDPt.h = theQDPt.v = 0;
  846.     LocalToGlobal(&theQDPt);
  847.     docPort = GetWindowGXPort(window);
  848.     GXConvertQDPoint(&theQDPt, docPort, &theGXPt);
  849.     FixedPointToShort(&theGXPt, &theQDPt);
  850.     return theQDPt;
  851. }
  852.  
  853. void SetShapeMainPort(JuggleHandle aJuggle, gxShape shape)
  854. {
  855.     gxViewPort    aPort;
  856.     
  857.     aPort = (*aJuggle)->docPort;
  858.     SetDeepShapeViewPorts(shape, 1, &aPort);
  859. }
  860.  
  861. void SetShapeFadePorts(JuggleHandle aJuggle, gxShape shape)
  862. {
  863.     gxViewPort    fadePorts[2];
  864.     
  865.     fadePorts[0] = (*aJuggle)->beforePort;
  866.     fadePorts[1] = (*aJuggle)->afterPort;
  867.     SetDeepShapeViewPorts(shape, 2, fadePorts);
  868. }
  869.  
  870. void SetInkBlendMode(gxInk theInk, short percent)
  871. {
  872.     gxTransferMode theMode;
  873.     
  874.     GXGetInkTransfer(theInk, &theMode);
  875.     
  876.     // Straight out of IM: Objects p. 5-44
  877.     theMode.flags = gxSingleComponentTransfer;
  878.     theMode.component[0].mode = gxBlendMode;
  879.     
  880.     theMode.component[0].flags = 0;
  881.     theMode.component[0].sourceMinimum = 0;
  882.     theMode.component[0].sourceMaximum = gxColorValue1;
  883.     theMode.component[0].deviceMinimum = 0;
  884.     theMode.component[0].deviceMaximum = gxColorValue1;
  885.     
  886.     theMode.component[0].clampMinimum = 0;
  887.     theMode.component[0].clampMaximum = gxColorValue1;
  888.     theMode.component[0].operand = 
  889.                     (((unsigned long)gxColorValue1) * percent) / 100;
  890.     
  891.     GXSetInkTransfer(theInk, &theMode);
  892. }
  893.  
  894. void ResetJuggleContentSize(JuggleHandle aJuggle)
  895. {
  896.     short    counts, jugglers;
  897.     Point    shortGrid;
  898.     
  899.     FixedPointToShort(&(*aJuggle)->gridPt, &shortGrid);
  900.     counts = (*aJuggle)->numCounts;
  901.     jugglers = (*aJuggle)->numJugglers;
  902.     (*aJuggle)->contentSize.h = ((2 * counts) + 1) * shortGrid.h + 1;
  903.     (*aJuggle)->contentSize.v = jugglers * shortGrid.v;
  904. }
  905.  
  906. // Get the picture that contains the throws
  907. gxShape GetDocThrowsPict(WindowPtr wind)
  908. {
  909.     return (*GetWindowJuggle(wind))->throwsPict;
  910. }
  911.  
  912. // Get the picture that contains the faded throws
  913. gxShape GetDocFadedThrowsPict(WindowPtr wind)
  914. {
  915.     return (*GetWindowJuggle(wind))->fadedThrowsPict;
  916. }
  917.